package breakthrough;

import java.util.ArrayList;
import java.util.Collections;

/**
 * Defines all the artificial intelligence methods and strategies.
 * @author ADZongo
 *
 */
public class AIManager
{
	private static final int MAX_DEPTH = 50;
	private static final int MAX_TIME_ALLOWED_MICROSECONDS = 5000000;
	public static final int PLUS_INFINITY = Integer.MAX_VALUE;
	public static final int MINUS_INFINITY = Integer.MIN_VALUE;
	Player minPlayer;
	Player maxPlayer;
	
	/**
	 * Minimax algorithm to determine the best move to play for the player max (the computer).
	 * @param b
	 * @return The score of the best board to move to.
	 */
	public Board minimaxAlphaBeta(Board aBoard, int depth, StopWatch stopWatch, int alpha, int beta, Player aPlayer)
	{
		
		// Test terminal state
		if (depth == MAX_DEPTH || (stopWatch.getElapsedTime() >= MAX_TIME_ALLOWED_MICROSECONDS))
			return BoardEvaluator.evaluateBoard(aBoard, aPlayer, maxPlayer);
		
		// Get all successors.
		ArrayList<Board> successors = MoveManager.getPossibleBoards(aBoard, aPlayer, maxPlayer);
		
		if (isTerminalBoard(aBoard, successors.size()))
			return BoardEvaluator.evaluateBoard(aBoard, aPlayer, maxPlayer);
		
		// Sort the successors for the alpha-beta pruning to be more efficient.
		Collections.sort(successors);
		
		// Best board to play from successors
		Board bestBoard = successors.get(0);
		
		for (Board child : successors)
		{
			if (aPlayer.equals(maxPlayer))
			{
				alpha = Math.max(alpha, minimaxAlphaBeta(child, depth + 1, stopWatch, alpha, beta, minPlayer).getBoardValue());
				if (alpha >= beta)
				{
					bestBoard = new Board(child);
					break;
					//return new Board(child);//return alpha;
				}
				//return bestBoard;//return alpha;
			}
			else
			{
				beta = Math.min(beta, minimaxAlphaBeta(child, depth + 1, stopWatch, alpha, beta, maxPlayer).getBoardValue());
				if (alpha >= beta)
				{
					bestBoard = new Board(child);
					break;
					//return beta;
				}
				//return bestBoard;//return beta;
			}
		}
		
		return bestBoard;
	}
	
	/**
	 * If the board is in a game over state or if no valid move is possible anymore.
	 * @return
	 */
	//public boolean isTerminalBoard(Board aBoard, Player aPlayer)
	public boolean isTerminalBoard(Board aBoard, int successorsCount)
	{
		return aBoard.hasGameOverState() || successorsCount == 0;
	}
	
	/**
	 * Sets the min player with its color.
	 * @param aPlayer
	 */
	public void setMinPlayer(Player aPlayer)
	{
		this.minPlayer = aPlayer;
	}
	
	/**
	 * Sets the max player with its color.
	 * @param aPlayer
	 */
	public void setMaxPlayer(Player aPlayer)
	{
		this.maxPlayer = aPlayer;
	}
}
